Code Should Be Obvious
「コードを明白にせよ」
コードが明白である
あまり考えずにコードを読むことができる
コードの動作や意味に関する最初の推測が正しいこと
コードに関する必要な情報を集めるのに多くの時間や労力を費やす
作業効率が下がる
誤解やバグの可能性
たとえ、自分には明白に見えてても
コードを明白にするテクニック
コードの動作を明確にし、コメントの必要性を軽減する
似たようなことを似たような方法で行うことで、読み手にパターンを認識させる
e.g. 関数パラメータのコメントを、パラメータの説明ごとに改行する
e.g. メソッド内のコードブロックを区切る
e.g. 文の構文を明確にする
コメント
不足している情報を提供する
ただし、読み手の立場に立って以下を考える必要がある
何が読み手を混乱させるか
どのような情報が、その混乱を解消するか
イベントが発生したら、ある1つのモジュールが他の部分にイベントが発生したことを通知する
e.g. マウスボタンの押下、パケットの到着
他の部分は、通知を受け取ったら、事前に指定された関数やメソッドを呼び出す
制御の流れを追ったり、理解したりするのが難しい
イベントハンドラ関数は直接呼び出されることはない
イベントモジュールの呼び出し箇所を見つけても、具体的にどの関数が呼び出されるか分からない
解決策: イベントモジュールのインタフェースのコメントで、いつ呼び出されるかを示す
code:java
/**
* This method is invoked in the dispatch thread by a transport if a
* transport-level error prevents an RPC from completing.
*/
void Transport::RpcNotifier::failed() {
...
}
汎用的なコンテナとは、2つ以上の要素を1つのオブジェクトにまとめる汎用的なクラスのこと
e.g. Java の Pair や C++ の std::pair
code:java
return new Pair<Integer, Boolean>(currentTerm, false);
上記の例だと、 result.getKey() と result.getValue() で参照する必要があるが、これでは値の持つ意味が分からない
解決策: 汎用的なコンテナは使わず、特定の用途に特化した新しいクラスを定義する
要素に意味のある名前を付ける
コメントで情報を補足することも可能
宣言と実際の型が異なる
e.g.
code:java
private List<Message> incomingMessageList;
...
incomingMessageList = new ArrayList<Message>();
変数は List として宣言されているが実際の値は ArrayList
List は ArrayList のスーパークラスなのでコンパイルは通る
List と ArrayList では扱い方が異なるので、読み手に誤解を与え得る
Java の ArrayList は、List の他のサブクラスと異なるパフォーマンスとスレッドセーフの特性を持っている 解決策: 宣言と実際の型は一致させる
読者の期待に反するコード
e.g.
code:java
public static void main(String[] args) {
...
new RaftClient(myAddress, serverAddresses);
}
通常、メインプログラムが return するとアプリケーションは終了する
しかし上記のコードでは、RaftClient コンストラクタは追加のスレッドを作成し、アプリケーションのメインスレッドが終了しても動作し続ける 解決策: 読み手が期待しない挙動の場合、コメントで補足する
e.g. RaftClient コンストラクタのインタフェース or new RaftClient(...) の直前にアプリケーションが他のスレッドで実行することを記述する
hr.icon
要約
コードが明白である = そのコードに関する重要な情報を常に読み手が持っている
コードが明白でない = そのコードに関する重要な情報を読み手が持っていない コードを明白にする3つの方法
抽象化 や特殊なケースを排除するなど、設計のテクニックを用いて必要な情報を減らす 読み手が既知の情報を活用する(慣習に沿う、期待通りの挙動をする etc...)
コード内で必要な情報を示す(良い名前やコメントを付ける etc...)